﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Eniux.Windows.ThreeDEngine.Base.CameraControllers;
using System.Windows.Markup;
using System.Windows.Media.Media3D;
using Eniux.Windows.ThreeDEngine.Helper;
using System.Diagnostics;
using System.Windows.Media.Animation;
using System.Collections.Specialized;
using Eniux.Windows.ThreeDEngine.Visual3Ds;
using Eniux.Windows.ThreeDEngine.AttachObject;
using System.ComponentModel;

namespace Eniux.Windows.ThreeDEngine.Base
{
    [ContentProperty("Children")]
    [TemplatePart(Name = "PART_CameraController", Type = typeof(CameraController))]
    [TemplatePart(Name = "PART_AdornerLayer", Type = typeof(AdornerDecorator))]
    [TemplatePart(Name = "PART_CoordinateView", Type = typeof(Viewport3D))]
    [TemplatePart(Name = "PART_ViewCubeViewport", Type = typeof(Viewport3D))]
    [Localizability(LocalizationCategory.NeverLocalize)]
    public partial class EniuxViewport3D : ItemsControl, IEniuxViewport3D 
    {

        #region 私有变量
        /// <summary>
        /// 装饰器层名字
        /// </summary>
        private const string PartAdornerLayer = "PART_AdornerLayer";

        /// <summary>
        ///  相机控制器名字
        /// </summary>
        private const string PartCameraController = "PART_CameraController";

        /// <summary>
        /// 坐标系统名字
        /// </summary>
        private const string PartCoordinateView = "PART_CoordinateView";


        /// <summary>
        ///   帧速率秒表
        /// </summary>
        private readonly Stopwatch fpsWatch = new Stopwatch();

        /// <summary>
        ///   顶光
        /// </summary>
        private readonly DirectionalLight headLight = new DirectionalLight { Color = Colors.White };

        /// <summary>
        ///  所有光
        /// </summary>
        private readonly Model3DGroup lights;

        /// <summary>
        ///   正交相机
        /// </summary>
        private readonly OrthographicCamera orthographicCamera;

        /// <summary>
        ///  透视相机
        /// </summary>
        private readonly PerspectiveCamera perspectiveCamera;

        /// <summary>
        ///  3D视窗
        /// </summary>
        private readonly Viewport3D viewport;

        /// <summary>
        ///  装饰器层
        /// </summary>
        private AdornerDecorator adornerLayer;

        /// <summary>
        ///   相机控制器
        /// </summary>
        private CameraController cameraController;

        /// <summary>
        ///   光系统
        /// </summary>
        private Model3DGroup coordinateSystemLights;

        /// <summary>
        ///   坐标系统
        /// </summary>
        private Viewport3D coordinateView;

        /// <summary>
        ///  当前相机
        /// </summary>
        private Camera currentCamera;

        /// <summary>
        ///  帧数
        /// </summary>
        private int frameCounter;

        /// <summary>
        ///   帧更新信息
        /// </summary>
        private int infoFrameCounter;

        /// <summary>
        ///   The view cube.
        /// </summary>
        private ViewCubeVisual3D viewCube;

        /// <summary>
        ///   ViewCube光系统
        /// </summary>
        private Model3DGroup viewCubeLights;

        /// <summary>
        ///   ViewCube3D视窗
        /// </summary>
        private Viewport3D viewCubeViewport;
        #endregion

        #region 属性注册

        #region CurrentPosition（当前位置）
        /// <summary>
        ///  当前位置属性
        /// </summary>
        public static readonly DependencyProperty CurrentPositionProperty =
            DependencyProperty.Register(
                "CurrentPosition",
                typeof(Point3D),
                typeof(EniuxViewport3D),
                new FrameworkPropertyMetadata(
                    new Point3D(0, 0, 0), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        /// <summary>
        /// 获取或设置当前位置
        /// </summary>
        public Point3D CurrentPosition
        {
            get { return (Point3D)GetValue(CurrentPositionProperty); }
            set { SetValue(CurrentPositionProperty, value); }
        } 
        #endregion

        #region DebugInfo（调试信息）
        /// <summary>
        /// 调试信息属性
        /// </summary>
        public static readonly DependencyProperty DebugInfoProperty = DependencyProperty.Register(
            "DebugInfo", typeof(string), typeof(EniuxViewport3D), new UIPropertyMetadata(null));

        /// <summary>
        /// 获取或设置当前调试信息
        /// </summary>
        public string DebugInfo
        {
            get { return (string)GetValue(DebugInfoProperty); }
            set { SetValue(DebugInfoProperty, value); }
        } 
        #endregion

        #region IsHeadLightEnabled（开启头光）
        /// <summary>
        ///   开启头光属性
        /// </summary>
        public static readonly DependencyProperty EnableHeadLightProperty =
            DependencyProperty.Register(
                "IsHeadLightEnabled",
                typeof(bool),
                typeof(EniuxViewport3D),
                new UIPropertyMetadata(false, HeadlightChanged));

        /// <summary>
        /// 获取或设置开启头光
        /// </summary>
        public bool IsHeadLightEnabled
        {
            get { return (bool)GetValue(EnableHeadLightProperty); }
            set { SetValue(EnableHeadLightProperty, value); }
        } 
        #endregion

        #region FieldOfViewText（查看文本）
        /// <summary>
        ///   查看文本属性
        /// </summary>
        public static readonly DependencyProperty FieldOfViewTextProperty =
            DependencyProperty.Register(
                "FieldOfViewText", typeof(string), typeof(EniuxViewport3D), new UIPropertyMetadata(null));

        /// <summary>
        /// 获取或设置查看文本
        /// </summary>
        public string FieldOfViewText
        {
            get { return (string)GetValue(FieldOfViewTextProperty); }
            set { SetValue(FieldOfViewTextProperty, value); }
        } 
        #endregion

        #region FrameRate（帧频率）
        /// <summary>
        ///   帧速率属性：FrameRate
        /// </summary>
        public static readonly DependencyProperty FrameRateProperty = DependencyProperty.Register(
            "FrameRate", typeof(int), typeof(EniuxViewport3D));

        /// <summary>
        /// 获取或设置帧频率
        /// </summary>
        public int FrameRate
        {
            get { return (int)GetValue(FrameRateProperty); }
            set { SetValue(FrameRateProperty, value); }
        } 
        #endregion

        #region FrameRateText（帧频率文本）
        /// <summary>
        ///   帧速率文本属性：FrameRateText
        /// </summary>
        public static readonly DependencyProperty FrameRateTextProperty = DependencyProperty.Register(
            "FrameRateText", typeof(string), typeof(EniuxViewport3D), new UIPropertyMetadata(null));

        /// <summary>
        /// 获取或设置帧频率文本
        /// </summary>
        public string FrameRateText
        {
            get { return (string)GetValue(FrameRateTextProperty); }
            set { SetValue(FrameRateTextProperty, value); }
        } 
        #endregion

        #region InfoBackground（）
        /// <summary>
        ///   信息背景属性：InfoBackground
        /// </summary>
        public static readonly DependencyProperty InfoBackgroundProperty = DependencyProperty.Register(
            "InfoBackground",
            typeof(Brush),
            typeof(EniuxViewport3D),
            new UIPropertyMetadata(new SolidColorBrush(Color.FromArgb(0x80, 0xff, 0xff, 0xff))));

        /// <summary>
        /// 获取或设置
        /// </summary>
        public Brush InfoBackground
        {
            get { return (Brush)GetValue(InfoBackgroundProperty); }
            set { SetValue(InfoBackgroundProperty, value); }
        } 
        #endregion

        #region IsChangeFieldOfViewEnabled（是否启用改变）
        /// <summary>
        ///   是否启用改变
        /// </summary>
        public static readonly DependencyProperty IsChangeFieldOfViewEnabledProperty =
            DependencyProperty.Register(
                "IsChangeFieldOfViewEnabled", typeof(bool), typeof(EniuxViewport3D), new UIPropertyMetadata(true));

        /// <summary>
        /// 获取或设置是否启用改变
        /// </summary>
        public bool IsChangeFieldOfViewEnabled
        {
            get { return (bool)GetValue(IsChangeFieldOfViewEnabledProperty); }
            set { SetValue(IsChangeFieldOfViewEnabledProperty, value); }
        } 
        #endregion

        #region Orthographic（正交）
        /// <summary>
        ///  是否正交属性
        /// </summary>
        public static readonly DependencyProperty OrthographicProperty = DependencyProperty.Register(
            "Orthographic", typeof(bool), typeof(EniuxViewport3D), new UIPropertyMetadata(false, OrthographicChanged));

        /// <summary>
        /// 获取或设置是否正交
        /// </summary>
        public bool Orthographic
        {
            get { return (bool)GetValue(OrthographicProperty); }
            set { SetValue(OrthographicProperty, value); }
        } 
        #endregion

        #region OrthographicToggleGesture（正交）
        /// <summary>
        ///  正交属性：OrthographicToggleGesture
        /// </summary>
        public static readonly DependencyProperty OrthographicToggleGestureProperty =
            DependencyProperty.Register(
                "OrthographicToggleGesture",
                typeof(InputGesture),
                typeof(EniuxViewport3D),
                new UIPropertyMetadata(new KeyGesture(Key.O, ModifierKeys.Control | ModifierKeys.Shift)));
        /// <summary>
        /// 获取或设置正交
        /// </summary>
        public InputGesture OrthographicToggleGesture
        {
            get { return (InputGesture)GetValue(OrthographicToggleGestureProperty); }
            set { SetValue(OrthographicToggleGestureProperty, value); }
        } 
        #endregion

        #region ShowCoordinateSystem（是否显示坐标系统）
        /// <summary>
        /// 是否显示坐标系统属性
        /// </summary>
        public static readonly DependencyProperty ShowCoordinateSystemProperty =
            DependencyProperty.Register(
                "ShowCoordinateSystem", typeof(bool), typeof(EniuxViewport3D), new UIPropertyMetadata(false));

        /// <summary>
        /// 获取或设置是否显示坐标系统
        /// </summary>
        public bool ShowCoordinateSystem
        {
            get { return (bool)GetValue(ShowCoordinateSystemProperty); }
            set { SetValue(ShowCoordinateSystemProperty, value); }
        } 
        #endregion

        #region ShowFieldOfView（是否显示视场）
        /// <summary>
        /// 是否显示视场属性
        /// </summary>
        public static readonly DependencyProperty ShowFieldOfViewProperty =
            DependencyProperty.Register(
                "ShowFieldOfView",
                typeof(bool),
                typeof(EniuxViewport3D),
                new UIPropertyMetadata(false, ShowFieldOfViewChanged));

        /// <summary>
        /// 获取或设置是否显示视场
        /// </summary>
        public bool ShowFieldOfView
        {
            get { return (bool)GetValue(ShowFieldOfViewProperty); }
            set { SetValue(ShowFieldOfViewProperty, value); }
        } 
        #endregion

        #region ShowFrameRate（显示帧速率）
        /// <summary>
        /// 显示帧速率属性
        /// </summary>
        public static readonly DependencyProperty ShowFrameRateProperty = DependencyProperty.Register(
            "ShowFrameRate", typeof(bool), typeof(EniuxViewport3D), new UIPropertyMetadata(false));

        /// <summary>
        /// 获取或设置是否显示帧速率
        /// </summary>
        public bool ShowFrameRate
        {
            get { return (bool)GetValue(ShowFrameRateProperty); }
            set { SetValue(ShowFrameRateProperty, value); }
        } 
        #endregion

        #region ShowTriangleCountInfo（是否显示三角形数量信息）
        /// <summary>
        ///  是否显示三角形数量信息属性
        /// </summary>
        public static readonly DependencyProperty ShowTriangleCountInfoProperty =
            DependencyProperty.Register(
                "ShowTriangleCountInfo", typeof(bool), typeof(EniuxViewport3D), new UIPropertyMetadata(false));

        /// <summary>
        /// 获取或设置是否显示三角形数量信息
        /// </summary>
        public bool ShowTriangleCountInfo
        {
            get { return (bool)GetValue(ShowTriangleCountInfoProperty); }
            set { SetValue(ShowTriangleCountInfoProperty, value); }
        } 
        #endregion

        #region TriangleCountInfo（三角形数量信息）
        /// <summary>
        /// 三角形数量信息属性
        /// </summary>
        public static readonly DependencyProperty TriangleCountInfoProperty =
            DependencyProperty.Register(
                "TriangleCountInfo", typeof(string), typeof(EniuxViewport3D), new UIPropertyMetadata(null));

        /// <summary>
        /// 获取或设置三角形数量信息属性
        /// </summary>
        public string TriangleCountInfo
        {
            get { return (string)GetValue(TriangleCountInfoProperty); }
            set { SetValue(TriangleCountInfoProperty, value); }
        } 
        #endregion

        #endregion

        #region 构造、析构

        /// <summary>
        /// 默认静态构造函数
        /// </summary>
        static EniuxViewport3D()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(EniuxViewport3D), new FrameworkPropertyMetadata(typeof(EniuxViewport3D)));
            ClipToBoundsProperty.OverrideMetadata(typeof(EniuxViewport3D), new FrameworkPropertyMetadata(true));
            OrthographicToggleCommand = new RoutedCommand();
            AttachCamera.AddOwner(typeof(EniuxViewport3D));
            AttachViewCube.AddOwner(typeof(EniuxViewport3D));
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public EniuxViewport3D()
        {
            // The Viewport3D must be created here since the Children collection is attached directly
            viewport = new Viewport3D();

            // viewport.SetBinding(UIElement.IsHitTestVisibleProperty, new Binding("IsViewportHitTestVisible") { Source = this });
            // viewport.SetBinding(UIElement.ClipToBoundsProperty, new Binding("ClipToBounds") { Source = this });

            // headlight
            lights = new Model3DGroup();
            viewport.Children.Add(new ModelVisual3D { Content = lights });

            perspectiveCamera = new PerspectiveCamera();
            CameraHelper.Reset(perspectiveCamera);
            orthographicCamera = new OrthographicCamera();
            CameraHelper.Reset(orthographicCamera);

            Camera = Orthographic ? (ProjectionCamera)orthographicCamera : perspectiveCamera;

            // http://blogs.msdn.com/wpfsdk/archive/2007/01/15/maximizing-wpf-3d-performance-on-tier-2-hardware.aspx
            // RenderOptions.EdgeMode?

            // start a watch for FPS calculations
            fpsWatch.Start();

            // Using the rendering event to calculate FPS
            CompositionTarget.Rendering += CompositionTargetRendering;
            Loaded += Viewport3DLoaded;
            Unloaded += Viewport3DUnloaded;

            CommandBindings.Add(new CommandBinding(ApplicationCommands.Copy, CopyHandler));
            CommandBindings.Add(new CommandBinding(OrthographicToggleCommand, OrthographicToggle));
        }

        #endregion


        #region 公共属性

        /// <summary>
        /// 
        /// </summary>
        public static RoutedCommand OrthographicToggleCommand { get; private set; }

        /// <summary>
        /// 获取或设置相机
        /// </summary>
        public ProjectionCamera Camera
        {
            get
            {
                return Viewport.Camera as ProjectionCamera;
            }

            set
            {
                if (currentCamera != null)
                {
                    currentCamera.Changed -= CameraPropertyChanged;
                }

                Viewport.Camera = value;

                currentCamera = Viewport.Camera;
                currentCamera.Changed += CameraPropertyChanged;
            }
        }

        /// <summary>
        /// 获取或设置相机控制器
        /// </summary>
        public CameraController CameraController
        {
            get{return cameraController;}
        }

        /// <summary>
        /// 获取或设置3D视窗的所有元素
        /// </summary>
        public Visual3DCollection Children
        {
            get{ return viewport.Children;}
        }

        /// <summary>
        /// 获取所有光
        /// </summary>
        public Model3DGroup Lights
        {
            get{return lights;}
        }

        /// <summary>
        /// 获取当前3D视窗
        /// </summary>
        public Viewport3D Viewport
        {
            get{return viewport;}
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 改变相机位置和方向
        /// </summary>
        /// <param name="newPosition"></param>
        /// <param name="newDirection"></param>
        /// <param name="newUpDirection"></param>
        /// <param name="animationTime"></param>
        public void SetView(Point3D newPosition, Vector3D newDirection, Vector3D newUpDirection, double animationTime)
        {
            CameraHelper.AnimateTo(Camera, newPosition, newDirection, newUpDirection, animationTime);
        }

        /// <summary>
        /// 改变相机方向
        /// </summary>
        /// <param name="newDirection">方向</param>
        /// <param name="animationTime">动画时间</param>
        public void ChangeCameraDirection(Vector3D newDirection, double animationTime = 0)
        {
            cameraController.ChangeDirection(newDirection, animationTime);
        }

        /// <summary>
        ///重置相机
        /// </summary>
        public void ResetCamera()
        {
            cameraController.ResetCamera();
        }

        /// <summary>
        /// 添加指定的Visual3D对象
        /// </summary>
        /// <param name="v">Visual3D对象</param>
        public void Add(Visual3D v)
        {
            if (!Viewport.Children.Contains(v))
            {
                Viewport.Children.Add(v);
            }
        }

        /// <summary>
        /// 移除指定的Visual3D对象
        /// </summary>
        /// <param name="v">要移除的Visual3D对象</param>
        public void Remove(Visual3D v)
        {
            if (Viewport.Children.Contains(v))
            {
                Viewport.Children.Remove(v);
            }
        }

        /// <summary>
        /// 清空视窗内容
        /// </summary>
        public void ClearChildren()
        {
            Viewport.Children.Clear();
        }

        /// <summary>
        /// 拷贝视窗内容到剪贴板
        /// </summary>
        public void Copy()
        {
            Viewport3DHelper.Copy(
                Viewport, Viewport.ActualWidth * 2, Viewport.ActualHeight * 2, Brushes.White, 2);
        }

        /// <summary>
        /// 以Xaml格式拷贝视窗内容到剪贴板
        /// </summary>
        public void CopyXaml()
        {
           // Clipboard.SetText(XamlHelper.GetXaml(Viewport.Children));
        }

        /// <summary>
        /// 以指定文件名导出视窗内容
        /// </summary>
        /// <param name="fileName">文件名</param>
        public void Export(string fileName)
        {
            Viewport3DHelper.Export(Viewport, fileName, Background);
        }

        /// <summary>
        /// 查找最近的对象
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="pos"></param>
        /// <param name="normal"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool FindNearest(Point pt, out Point3D pos, out Vector3D normal, out DependencyObject obj)
        {
            return Viewport3DHelper.FindNearest(Viewport, pt, out pos, out normal, out obj);
        }

        /// <summary>
        /// 查找最近的点
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public Point3D? FindNearestPoint(Point pt)
        {
            return Viewport3DHelper.FindNearestPoint(Viewport, pt);
        }

        /// <summary>
        /// 查找最近的Visual3D对象
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public Visual3D FindNearestVisual(Point pt)
        {
            return Viewport3DHelper.FindNearestVisual(Viewport, pt);
        }

        /// <summary>
        /// 请求模板
        /// </summary>
        public override void OnApplyTemplate()
        {
            if (adornerLayer == null)
            {
                adornerLayer = Template.FindName(PartAdornerLayer, this) as AdornerDecorator;
                if (adornerLayer != null)
                {
                    adornerLayer.Child = viewport;
                }
            }

            Debug.Assert(
                adornerLayer != null, string.Format("{0} is missing from the template.", PartAdornerLayer));

            if (cameraController == null)
            {
                cameraController = Template.FindName(PartCameraController, this) as CameraController;
                if (cameraController != null)
                {
                    cameraController.Viewport = Viewport;
                }
            }

            Debug.Assert(
                cameraController != null, string.Format("{0} is missing from the template.", PartCameraController));

            if (coordinateView == null)
            {
                coordinateView = Template.FindName(PartCoordinateView, this) as Viewport3D;

                coordinateSystemLights = new Model3DGroup();

                // coordinateSystemLights.Children.Add(new DirectionalLight(Colors.White, new Vector3D(1, 1, 1)));
                // coordinateSystemLights.Children.Add(new AmbientLight(Colors.DarkGray));
                coordinateSystemLights.Children.Add(new AmbientLight(Colors.LightGray));

                if (coordinateView != null)
                {
                    coordinateView.Camera = new PerspectiveCamera();
                    coordinateView.Children.Add(new ModelVisual3D { Content = coordinateSystemLights });
                }
            }

            Debug.Assert(
                coordinateView != null, string.Format("{0} is missing from the template.", PartCoordinateView));

            if (viewCubeViewport == null)
            {
                viewCubeViewport = Template.FindName(PartViewCubeViewport, this) as Viewport3D;

                viewCubeLights = new Model3DGroup();
                viewCubeLights.Children.Add(new AmbientLight(Colors.White));
                if (viewCubeViewport != null)
                {
                    viewCubeViewport.Camera = new PerspectiveCamera();
                    viewCubeViewport.Children.Add(new ModelVisual3D { Content = viewCubeLights });
                    viewCubeViewport.MouseEnter += ViewCubeViewportMouseEnter;
                    viewCubeViewport.MouseLeave += ViewCubeViewportMouseLeave;
                }

                viewCube = Template.FindName(PartViewCube, this) as ViewCubeVisual3D;
                if (viewCube != null)
                {
                    viewCube.Viewport = Viewport;
                }
            }

            Debug.Assert(
                coordinateView != null, string.Format("{0} is missing from the template.", PartCoordinateView));

            // update the coordinateview camera
            OnCameraChanged();

            // add the default headlight
            OnHeadlightChanged();
            base.OnApplyTemplate();
        }

        #endregion

        #region 方法

        /// <summary>
        /// 相机属性改变时，调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CameraPropertyChanged(object sender, EventArgs e)
        {
            // Raise notification
            RaiseCameraChangedEvent();

            // Update the CoordinateView camera and the headlight direction
            OnCameraChanged();
        }

        /// <summary>
        /// 当相机改变时调用该方法
        /// </summary>
        protected virtual void OnCameraChanged()
        {
            // update the camera of the coordinate system
            if (coordinateView != null)
            {
                CameraHelper.CopyDirectionOnly(Camera, coordinateView.Camera as PerspectiveCamera, 30);
            }

            // update the camera of the view cube
            if (viewCubeViewport != null)
            {
                CameraHelper.CopyDirectionOnly(Camera, viewCubeViewport.Camera as PerspectiveCamera, 20);
            }

            // update the headlight and coordinate system light
            if (Camera != null)
            {
                if (headLight != null)
                {
                    headLight.Direction = Camera.LookDirection;
                }

                if (coordinateSystemLights != null)
                {
                    var cshl = coordinateSystemLights.Children[0] as DirectionalLight;
                    if (cshl != null)
                    {
                        cshl.Direction = Camera.LookDirection;
                    }
                }
            }

            if (ShowFieldOfView)
            {
                UpdateFieldOfViewInfo();
            }

            if (ShowCameraInfo)
            {
                UpdateCameraInfo();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected virtual void RaiseCameraChangedEvent()
        {
            // e.Handled = true;
            var args = new RoutedEventArgs(CameraChangedEvent);
            RaiseEvent(args);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            // base.OnItemsChanged(e);
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (var v in e.NewItems)
                    {
                        Add(v as Visual3D);
                    }

                    break;
                case NotifyCollectionChangedAction.Move:
                    break;
                case NotifyCollectionChangedAction.Remove:
                    foreach (var v in e.OldItems)
                    {
                        Remove(v as Visual3D);
                    }

                    break;
                case NotifyCollectionChangedAction.Replace:
                    break;
                case NotifyCollectionChangedAction.Reset:
                    ClearChildren();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            var pt = e.GetPosition(this);
            var pos = FindNearestPoint(pt);
            if (pos != null)
            {
                CurrentPosition = pos.Value;
            }
            else
            {
                var p = Viewport3DHelper.UnProject(Viewport, pt);
                if (p != null)
                {
                    CurrentPosition = p.Value;
                }
            }
        }

        /// <summary>
        /// 相机旋转模式改变时，调用该方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void CameraRotationModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EniuxViewport3D)d).OnCameraRotationModeChanged();
        }

        /// <summary>
        /// 相机旋转模式发生更改时调用该方法
        /// </summary>
        private void OnCameraRotationModeChanged()
        {
            if (AttachCamera.GetCameraRotationMode(this) != CameraRotationMode.Trackball)
            {
                cameraController.ResetCameraUpDirection();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void HeadlightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EniuxViewport3D)d).OnHeadlightChanged();
        }

        /// <summary>
        /// 
        /// </summary>
        protected void OnHeadlightChanged()
        {
            if (lights == null)
            {
                return;
            }

            if (IsHeadLightEnabled && !lights.Children.Contains(headLight))
            {
                lights.Children.Add(headLight);
            }

            if (!IsHeadLightEnabled && lights.Children.Contains(headLight))
            {
                lights.Children.Remove(headLight);
            }
        }

        /// <summary>
        /// 正交相机改变时，调用该方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OrthographicChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EniuxViewport3D)d).OnOrthographicChanged();
        }

        /// <summary>
        /// 相机类型发生改变时调用该方法
        /// </summary>
        private void OnOrthographicChanged()
        {
            var oldCamera = Camera;
            if (Orthographic)
            {
                Camera = orthographicCamera;
            }
            else
            {
                Camera = perspectiveCamera;
            }

            CameraHelper.Copy(oldCamera, Camera);
        }


        /// <summary>
        /// 显示相机信息属性改变时，调用该方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void ShowCameraInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EniuxViewport3D)d).UpdateCameraInfo();
        }

        /// <summary>
        /// 更新相机信息
        /// </summary>
        private void UpdateCameraInfo()
        {
            CameraInfo = CameraHelper.GetInfo(Camera);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void ShowFieldOfViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((EniuxViewport3D)d).UpdateFieldOfViewInfo();
        }

        /// <summary>
        /// The update field of view info.
        /// </summary>
        private void UpdateFieldOfViewInfo()
        {
            var pc = Camera as PerspectiveCamera;
            FieldOfViewText = pc != null ? string.Format("FoV ∠ {0:0}°", pc.FieldOfView) : null;
        }

        /// <summary>
        /// CompositionTarget呈现事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CompositionTargetRendering(object sender, EventArgs e)
        {
            frameCounter++;
            if (ShowFrameRate && fpsWatch.ElapsedMilliseconds > 500)
            {
                FrameRate = (int)(frameCounter / (0.001 * fpsWatch.ElapsedMilliseconds));
                FrameRateText = FrameRate + " FPS";
                frameCounter = 0;
                fpsWatch.Reset();
                fpsWatch.Start();
            }

            // update the info fields every 100 frames
            // todo: should only update when the visual model of the Viewport3D changes
            infoFrameCounter++;
            if (ShowTriangleCountInfo && infoFrameCounter > 100)
            {
                int count = Viewport3DHelper.GetTotalNumberOfTriangles(viewport);
                TriangleCountInfo = string.Format("Triangles: {0}", count);
                infoFrameCounter = 0;
            }
        }

        /// <summary>
        /// 当3D视窗Loaded时调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Viewport3DLoaded(object sender, RoutedEventArgs e)
        {
            if (ZoomExtentsWhenLoaded)
            {
                ZoomExtents();
            }
        }

        /// <summary>
        /// 当3D视窗Unload时调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Viewport3DUnloaded(object sender, RoutedEventArgs e)
        {
        }

        /// <summary>
        /// 复制操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CopyHandler(object sender, ExecutedRoutedEventArgs e)
        {
            // var vm = Viewport3DHelper.GetViewMatrix(Camera);
            // double ar = ActualWidth / ActualHeight;
            // var pm = Viewport3DHelper.GetProjectionMatrix(Camera, ar);
            // double w = 2 / pm.M11;
            // pm.OffsetX = -1
            // ;
            // pm.M11 *= 2;
            // pm.M22 *= 2;
            // var mc = new MatrixCamera(vm, pm);
            // viewport.Camera = mc;
            Copy();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OrthographicToggle(object sender, ExecutedRoutedEventArgs e)
        {
            Orthographic = !Orthographic;
        }

        #endregion
    }
}
